using System;
using System.Collections.Generic;
using System.Drawing;

using Clandestine.Base;
using Clandestine.Graphics;

using Lime;

namespace Clandestine.Engines.Field.Collision
{	
	public partial class Hull
	{
		Rectangle bbox;
		List<Edge> edges;
		List<Point> points;
		
		object lockblob = new object();  // public functions handle the locking, priv don't!
		
		Point lastPoint = Point.Empty;
		
		public Hull(List<Point> points) { setup(points); }
		
		public List<Point> GetPoints() { lock (lockblob) { return new List<Point>(points); } }
		
		public void SetPoints(List<Point> points) { lock (lockblob) { setup(points); } }
		
		public bool Contains(Point p) { lock (lockblob) { return ((!bbox.Contains(p)) ? false : hullContains(p)); } }
		
		public Sprite Render(RenderList rl) { lock (lockblob) { return render(rl, bbox, points); } }

		
		private void setup(List<Point> points)
		{
			this.edges = new List<Edge>();
			this.points = points;
			
			Point old = Point.Empty;
			bool flag = false;
			
			foreach (Point p in points)
			{
				if (flag)
					edges.Add(new Edge(old, p));
				else
					flag = true;
				old = p;
			}
			edges.Add(new Edge(points[points.Count - 1], points[0]));
			
			bbox = BoundingBox.Create(points);
		}
		
		private bool hullContains(Point poi)
		{
			// Make a horizontal line across, with y set equal to poi.Y.
			// Find points where the line intersects with shape edges.
			// Go through each point (inc. poi!) from the left, and count how many we pass through before hitting
			//  poi.  If it's odd, poi is inside the shape -- if it's even, poi is outside!
			
			// (very thanks to the incredibly good diagram, Figure 1, at http://www.alienryderflex.com/polygon/)
			
			this.lastPoint = poi;
			
			int leftcount = 0;
			
			foreach (Edge ed in edges)
			{
				// y=mx+c => y-c=mx => x=(y-c)/m
				double x = (poi.Y - ed.c) / ed.m;
				
				// Is it in bounds?
				if (x >= ed.lx && x <= ed.gx)
					// Is it left of poi??
					if (x < poi.X)
						leftcount++;
			}
			
			return (leftcount % 2 == 1);
		}
		
		internal void forceDebugRender()
		{
			Point poi = lastPoint;
			
			GL.Color4(0f, 0f, 0f, 1f);
			
			GL.Begin(BeginMode.Lines);
			
			GL.Vertex2(0f, poi.Y);
			GL.Vertex2(10000f, poi.Y);
			
			GL.End();
			
			GL.PointSize(4f);
			
			GL.Begin(BeginMode.Points);
			
			foreach (Edge ed in edges)
			{
				// y=mx+c => y-c=mx => x=(y-c)/m
				double x = (poi.Y - ed.c) / ed.m;
				
				// Is it in bounds?
				if (x >= ed.lx && x < ed.gx)
				{
					// Is it left of poi??
					if (x < poi.X)
						GL.Color4(1f, 0f, 0f, 1f); // red
					else
						GL.Color4(0f, 1f, 0f, 1f); // green
				}
				else
					GL.Color4(0f, 0f, 1f, 1f); // blue
				
				GL.Vertex2(x, poi.Y);
			}
			
			GL.End();
		}
		

	}
}
